// Enumerate all debug symbols

// ----------------------------------------------------------------------------

#include "stdafx.h"

#include "DSymLoadError.h"

#include "DSymLoadEnum.h"


// ----------------------------------------------------------------------------

namespace DSymLoad
{

// ----------------------------------------------------------------------------

namespace
{

// ----------------------------------------------------------------------------

BOOL
CALLBACK
EnumSymbolsCallback(
    __in PSYMBOL_INFO pSymInfo,
    __in ULONG SymbolSize,
    __in_opt PVOID UserContext
)
{
    _ASSERT(UserContext);
    reinterpret_cast<IEnumSymbols *>(UserContext)->Callback(pSymInfo, SymbolSize);
    return TRUE;
}

// ----------------------------------------------------------------------------

}

// ----------------------------------------------------------------------------

void EnumAllSymbols(
    __in const CSettings &Settings,
    __in PCSTR szFileName,
    IEnumSymbols &EnumSymbols
)
{
    const CDbgHelp DbgHelp(Settings.GetLibPath());

    const DWORD nOptions = 
        SYMOPT_NO_PROMPTS |
        (Settings.IsUndName() ? SYMOPT_UNDNAME : 0) |
        (Settings.IsNoCpp() ? SYMOPT_NO_CPP : 0);
    DbgHelp.GetSymSetOptions()(nOptions);

    const HANDLE hProcess = ::GetCurrentProcess();

    PCSTR szSymPath = 
        Settings.GetSymPath().IsEmpty() ? nullptr : Settings.GetSymPath().GetString();
    if (!DbgHelp.GetSymInitialize()(hProcess, szSymPath, FALSE))
        throw MakeFunctionCallError("SymInitialize");

    const DWORD64 LoadedModule = 
        DbgHelp.GetSymLoadModuleEx()(
            hProcess,
            nullptr,
            szFileName,
            nullptr,
            0,
            0,
            nullptr,
            0);
    if (!LoadedModule)
        throw MakeFunctionCallError("SymLoadModuleEx");

    struct CUnloadModuleGuard
    {
        explicit CUnloadModuleGuard(
            __in const CDbgHelp &DbgHelp,
            __in DWORD64 LoadedModule
        )   : m_DbgHelp(DbgHelp)
            , m_LoadedModule(LoadedModule)
        {
        }
        ~CUnloadModuleGuard()
        {
            m_DbgHelp.GetSymUnloadModule64()(::GetCurrentProcess(), m_LoadedModule);
        }

        const CDbgHelp &m_DbgHelp;
        DWORD64 m_LoadedModule;
    };
    CUnloadModuleGuard UnloadModuleGuard(DbgHelp, LoadedModule);

    ULONG nErrorCode = ERROR_INTERNAL_ERROR;
    SYM_TYPE SymType = SymNone;

    static const DWORD g_Sizes[] = 
    {
        sizeof(IMAGEHLP_MODULE64),
        FIELD_OFFSET(IMAGEHLP_MODULE64, SourceIndexed), // new elements: 17-Dec-2003
        FIELD_OFFSET(IMAGEHLP_MODULE64, LoadedPdbName), // new elements: 07-Jun-2002
    };
    for (auto Size : g_Sizes)
    {
        _ASSERT(Size > FIELD_OFFSET(IMAGEHLP_MODULE64, SymType));
        _ASSERT(Size <= sizeof(IMAGEHLP_MODULE64));

        IMAGEHLP_MODULE64 ModuleInfo64;
        memset(&ModuleInfo64, 0, sizeof(ModuleInfo64));
        ModuleInfo64.SizeOfStruct = Size;
        if (DbgHelp.GetSymGetModuleInfo64()(hProcess, LoadedModule, &ModuleInfo64))
        {
            nErrorCode = ERROR_SUCCESS;
            SymType = ModuleInfo64.SymType;
            break;
        }

        nErrorCode = ::GetLastError();
    }
    if (nErrorCode != ERROR_SUCCESS)
        throw MakeFunctionCallError("SymGetModuleInfo64", "...", nErrorCode);

    switch (SymType)
    {
        case SymNone:
        case SymExport:
            throw CError("Debug symbols are not loaded");
    }

    const auto Result = 
        DbgHelp.GetSymEnumSymbols()(
            hProcess,
            LoadedModule,
            nullptr,
            &EnumSymbolsCallback,
            &EnumSymbols);
    if (!Result)
        throw MakeFunctionCallError("SymEnumSymbols");
}

// ----------------------------------------------------------------------------

}   // namespace DSymLoad

// ----------------------------------------------------------------------------
